﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using Ionic.Zip;
using FRW.Common.FileSystem;
using FRW.Common.Extensions;

namespace FRW.CreateTestDirectory
{
    public class Doc
    {
        public event EventHandler Finished;

        private string _destination;
        private string _source;
        private string _zipFilename;
        private bool _createZip;
        private bool _cancel = false;
        private int _filesize;
        private IStatusUi _statusUi;
        private ILog _log;
        private Thread _workerThread;
        private int _zipEntries;

        private int _fileCount = 0;
        private int _directoryCount = 0;

        public int Filesize
        {
            get { return _filesize; }
            set { _filesize = value; }
        }

        public bool CreateZip
        {
            get { return _createZip; }
            set { _createZip = value; }
        }

        public string ZipFilename
        {
            get { return _zipFilename; }
            set { _zipFilename = value; }
        }

        public string Destination
        {
            get { return _destination; }
            set { _destination = value; }
        }

        public string Source
        {
            get { return _source; }
            set { _source = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="statusUi"></param>
        public void SetStatusInterface(IStatusUi statusUi)
        {
            _statusUi = statusUi;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="log"></param>
        public void SetLogInterface(ILog log)
        {
            _log = log;
        }

        /// <summary>
        /// 
        /// </summary>
        public void Start()
        {
            if ( (_workerThread == null) || !_workerThread.IsAlive)
            {
                _workerThread = new Thread(() => { DoWork(); });
                _workerThread.Start();
            }
            else
            {
                _log.Log("Why are you trying to run me again!!!\n");
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public void Cancel()
        {
            _cancel = true;
            _workerThread.Abort();
            _log.Log("Operation Cancelled");
        }

        /// <summary>
        /// 
        /// </summary>
        private void DoWork()
        {
            int totalFilesDirectories = 0;
            int count = 0;
            DirectoryInfo sdi;

            string destination = _destination;
            string source = _source;
            string zipFilename = _zipFilename;
            bool createZip = _createZip;
            int filesize = _filesize;
            int steps = 1;

            _fileCount = 0;
            _directoryCount = 0;
            _zipEntries = 0;
            _cancel = false;

            if (!Directory.Exists(source))
            {
                _log.Log("Source folder does not exist\n");
                return;
            }

            if(createZip)
            {
                steps = 3;
            }

            sdi = new DirectoryInfo(source);

            if (!Directory.Exists(destination))
            {
                _log.Log("Destination folder does not exist - creating\n");
                try
                {
                    Directory.CreateDirectory(destination);
                }
                catch
                {
                    _log.Log("Cannot create destination directory\n");
                    return;
                }

                if (Directory.Exists(destination))
                {
                    _log.Log("Destination directory created\n");
                }
                else
                {
                    _log.Log("Cannot create destination directory\n");
                    return;
                }
            }

            string fileContents = CreateFileContents(filesize);

            DirectoryStructure fileList = new DirectoryStructure(source);

            totalFilesDirectories = fileList.Directories.Count() + fileList.Files.Count();

            // destination += @"\" + sdi.Name;
            destination += @"\Structure";

            _statusUi.DisplayStatusText("Creating Directory Structure (1/" + steps + ")");
            if (!Directory.Exists(destination))
            {
                Directory.CreateDirectory(destination);
            }

            foreach (DirectoryInfo di in fileList.Directories)
            {
                DirectoryInfo ndi = di.NewPath(source, destination);

                if (!ndi.Exists)
                {
                    ndi.Create();
                }

                if (_cancel == true)
                {
                    _log.Log("Operation Cancelled\n");
                    return;
                }

                count++;
                _directoryCount++;

                _statusUi.PercentageComplete(100 * count / totalFilesDirectories);
            }

            foreach (FileInfo file in fileList.Files)
            {
                FileInfo newFile = file.NewPath(source, destination);

                if (_cancel == true)
                {
                    _log.Log("Operation Cancelled\n");
                    return;
                }

                if (!newFile.Exists)
                {
                    using (StreamWriter stream = new StreamWriter(newFile.FullName))
                    {
                        stream.Write(fileContents);
                    }
                }

                count++;
                _fileCount++;

                _statusUi.PercentageComplete(100 * count / totalFilesDirectories);
            }

            _log.Log("Directory structure created\n");

            if (_createZip == true && !String.IsNullOrEmpty(zipFilename))
            {
                _statusUi.DisplayStatusText("Adding Files to Zip File (2/" + steps + ")");
                _log.Log("Creating zip file (" + zipFilename + ")\n");
                ZipFile zipfile = new ZipFile();
                zipfile.AddProgress += new EventHandler<AddProgressEventArgs>(zipfile_AddProgress);
                zipfile.SaveProgress += new EventHandler<SaveProgressEventArgs>(zipfile_SaveProgress);
                _log.Log("Adding files to Zip\n");
                zipfile.AddDirectory(destination);
                if (_cancel)
                {
                    return;
                }
                _log.Log("All files added to Zip\n");
                if (_cancel)
                {
                    return;
                }
                _statusUi.DisplayStatusText("Saving Zip File (3/" + steps + ")");
                _log.Log("Saving Zip file\n");
                if (_cancel)
                {
                    return;
                }
                zipfile.Save(zipFilename);
                if (_cancel)
                {
                    return;
                }
                _log.Log("Zip file saved\n");
                if (_cancel)
                {
                    return;
                }
                _log.Log("Zip file created (" + _zipFilename + ")\n");
            }

            _log.Log("Created " + _fileCount + " files\n");
            _log.Log("Created " + _directoryCount + " directories\n");
            _log.Log("Finished creating structure\n");

            OnFinished();
        }

        void zipfile_SaveProgress(object sender, SaveProgressEventArgs e)
        {
            if (_cancel == true)
            {
                e.Cancel = true;
            }
            else
            {
                switch (e.EventType)
                {
                    case ZipProgressEventType.Saving_AfterWriteEntry:
                        _statusUi.PercentageComplete(Convert.ToInt32(100 * e.EntriesSaved / e.EntriesTotal));
                        break;
                }
            }
        }

        void OnFinished()
        {
            _statusUi.Finished();

            if (Finished != null)
            {
                Finished.Invoke(this, new EventArgs());
            }
        }

        void zipfile_AddProgress(object sender, AddProgressEventArgs e)
        {
            if (_cancel == true)
            {
                e.Cancel = true;
            }
            else
            {
                switch (e.EventType)
                {
                    case ZipProgressEventType.Adding_AfterAddEntry:
                        _zipEntries++;
                        _statusUi.PercentageComplete(100 * _zipEntries / (_fileCount + _directoryCount));
                        break;
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="fileSize"></param>
        /// <returns></returns>
        private static string CreateFileContents(int fileSize)
        {
            string padding = ".";
            if (fileSize > 0)
            {
                padding = new string('.', fileSize);
            }

            return "Test File" + padding;
        }


    }
}
